perm filename HELP.DOC[AID,LSP]1 blob sn#478994 filedate 1980-08-10 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00017 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	                     Debugging Aids in LISP
C00005 00003	                         THE LISP EDITOR
C00028 00004	                   The Backspace (BS) Package
C00035 00005	                         The BRAKE Package
C00041 00006	                        THE DEBUG PACKAGE
C00054 00007	                        THE STEP PACKAGE
C00068 00008			      Features and Meta-features
C00071 00009					String
C00075 00010					MACRO
C00080 00011			   Further MACRO/MACRODEF features
C00082 00012					MACEX
C00083 00013				       REQUIRE
C00085 00014					DIRECT
C00087 00015					  ET
C00088 00016					 MAIL
C00089 00017				 Line Editor Loading
C00090 ENDMK
C⊗;
                     Debugging Aids in LISP
                     --------- ---- -- ----




          The following is a description  of  some  of  the  more

     sophisticated  debugging  aids  available in MACLISP at SAIL.

     Covered in this memo are:


          1.  The LISP Editor, written by R.P.Gabriel and T.Finin

          2.  The Backspace package, written by Jonl White

          3.  The Brake package, written by R.P.Gabriel

          4.  The Stepper package, written by R.P. Gabriel and Tim Finin

          5.  The Debug package, written by R.P. Gabriel and T.Finin.

	  6.  Random debugging features and meta-features.

          In each case, the  programs  are  FASLOADable  and  are

     located on the DSK [MAC,LSP] under EDIT.FAS, BS.FAS, BRAKE.FAS,

     STEP.FAS and DEBUG.FAS respectively.


          In addition, the file  HELP.FAS DSK [MAC LSP] can  be  FASLOADed

     into  a  LISP  to  setup  "autoload"  pointers to all of the

     debugging functions mentioned in this memo.  Then,  whenever

     any  of these functions is called, the appropriate file will

     be automatically loaded.



                         THE LISP EDITOR
                         --- ---- ------



          The following is a very brief introduction to  the  use
     of the LISP Editor.

                       Loading the Editor
                       ------- --- ------

     1). To run the LISP Editor, one simply types  (EDIT)
         or  (EDIT  FOO)  to  edit  the in-core function "FOO" or
         (EDIT FOO FOO BAR DSK (COM RPG)) to  edit  the  function
         "FOO" in file FOO.BAR in the directory of COM,RPG.

     2). (EDIT) or (EDIT FOO) or (EDIT FOO FOO BAR) or (EDIT  FOO
         FOO  BAR  DSK (COM RPG)) can be done in LISP's that have
         an autoload property for EDIT. Typing (EDIT) causes the
	 Editor to be initialized and entered. (EDIT1 <exp>) will make
	 <exp> the toplevel editable expression. (EDIT2 <var>) will
	 make (PROG2 (SETQ <var> <current value of var>) T) the 
	 toplevel while (EDIT2 (GET <var> <indicator>)) will make it:
	 (DEFPROP <var> <value> <indicator>).

     3). (EDITV <atom>) edits the value of <atom>; the editted expression
	 is actually (prog1 (setq <atom> <value of atom>) t).

     4). (EDITP <atom> <prop>) edits the <prop> property of <atom>; the
	 actual editted expression is (defprop <atom> <value> <prop>).

              How to Look at the Current Expression (CE)
              --- -- ---- -- --- ------- ----------  --

     P        prints  the  CE  using  the  current  print   depth
              (sublist cutoff) and print length (length cutoff)
     PP       pretty-prints the entire CE
     PS       pretty-prints the CE using the print depth cutoff
     W	      prints the "window" surrounding the CE. Thus if
	      window size is 2, it prints the 2 preceeding and 2 following
	      tokens around the CE, where "token" means expression or 
	      parenthesis.

     (WINDOW n) 
	      changes the window size to n.

     (PL n)   changes the print length to n (initially 5)
     (PD n)   changes the print depth to n (initially 2)

                         Changing the CE
                         -------- --- --

     (CR E1...En) changes the  CE  to  E1...En  (i.e. splices  in
                  E1...En), and makes the CE E1.
     (n E1...En)  n>0, changes the n-th  element  of  the  CE  to
                  E1...En
     (n E1...En)  n<0 changes the n-th element of the CE from the
                  end to E1...En
     (n)          n>0 deletes the n-th element of the CE
     (n)          n<0, deletes the n-th element from the end
     RI           moves the right parenthesis in one expression
     RO           moves the right parenthesis out one expression
     LI           similar to RI
     LO           similar to RO
     DELETE       deletes the CE  (if  the  CE  is  the  toplevel
                  expression, the Editor assumes that the user
		  wants to edit a different function and requests:

          (function name <file specifications>):

     The answer can be of several forms;  examples:
        1)  FOO - loads FOO from core
        2)  (FOO FOO BAR) - loads FOO from FOO.BAR
        3)  (FOO BAR DSK (COM RPG)) - loads FOO from  FOO.BAR  in
            the directory of COM,RPG.
        4)  NEW - gives a fresh top-level expression
        5)  cntrl-G - quits back to the Editor command decoder
        6)  UNDO - <see below>.

               Moving around within the Expression
               ------ ------ ------ --- ----------

     n        n>0 makes the new CE the n-th element of the CE
     n        n<0, makes the new CE the n-th element from the end
              of the CE
     ↑        makes the CE the immediate parent of the CE
     TOP      makes the CE the toplevel expression
     NX       makes the CE the next one after the CE
     BK       makes the CE the one before the CE
     MARK     marks the current location so that it can be JUMPed
              to by the command JUMP.  Note:  MARKing and JUMPing
              is not guaranteed  to  work  in  all  cases,  since
              modification  of  the thing being edited can render
              the MARK meaningless.
     JUMP     jumps to the last MARKed location
     UNMARK   forgets  where  the  last  MARK  was  set   (speeds
              execution)

                       Adding Expressions
                       ------ -----------
     (A n E1...En) puts E1...En after the n-th element of the CE
     (B n E1...En) puts E1...En before the n-th element of the CE
     (AI E1...En)  puts E1...En after the CE and makes E1 the new CE
     (BI E1...En)  puts E1...En before the CE and  makes  E1  the new CE
     (R exp1 exp2) replaces all occurrences of exp1 with exp2  in the CE, viewed
		   as a list, returns nil? if no occurrences found
     (TR exp1 exp2)replaces all occurrences of exp1 with exp2  in the CE, viewed
		   as a tree

                       Finding Expressions (i.e. changing the CE)
                       ------- -----------  ---  -------- --- --

     (F pat)    finds the next occurrence of  pat,  searching  in
                print order
     (BF pat)   finds the next occurrence of  pat,  searching  in
                inverse print order
     (F pat T)  finds the next occurrence of pat but looks at the
                topmost  elements  of  the  CE  first (useful for
                getting to PROG tags)
     (BF pat T) similar to above
     (F pat n)  finds the n-th occurrence of pat
     (BF pat n) similar to above
     F          finds the next  occurrence  of  the  last  search
                pattern
     BF         similar to above


                             Patterns
                             --------


          Pat, as used above, can contain any of the following:
           Element of pat         What it matches
           ------- -- ---         ---- -- -------

           atom                   atoms EQ to it
           list                   calls matcher recursively
           ?                      any   atom   or   single   list
                                  (i.e. an s-expression)
           ?X                     any  element;   binds   ?X   to
                                  whatever it matched
           *                      any   non-empty    string    of
                                  elements
           *X                     matches as *, but binds  *X  to
                                  the list of elements it matched
           =?X                    whatever ?X matched last time
           =*X                    whatever *X matched last time
           (RESTRICT  ?   P1...Pn)  any  element  satisfying  the
                                  predicates P1,...,Pn
	   ($R ? P1...Pn)	  same as above.
           (RESTRICT ?X P1...Pn)  similar to above but  binds  ?X
                                  to what it matched.
	   ($R ?X P1...Pn)	  same as above.
	   (⊗R  ...) 		  same as ($R ...)
	   ($R * P1...Pn)	  same as above but the list that * matches
				  must satisfy P1,...Pn.
	   ($R *X P1...Pn)	  similar to above
	   ($IR * P1...Pn)	  similar to above except that Pi is a predicate
				  that each element of * must satisfy.
	   ($IR *X ...)		  similar to above

          Note:  (A ?X IS A ?X) matches (a word is  a  word)  but
     not (a word is a sentence).  Simlarly for (*X is a *X).

                      Invoking the Matcher
                      -------- --- -------

     (MATCH pat)               attempts to match pat against the CE
     (MATCH pat var1 ... varn) attempts to match pat against the
			       CE while retaining the values of the
			       variables var1,..., varn. (E.g. 
			       (MATCH (* *A *B ?A) *A ?A).
     MATCH		       attempts to match the last pat against the
			       CE. Like F and BF above.
     REMATCH		       attempts to get the next match of pat against
			       the CE. Usually this only makes sense if
			       pat contains some * variables.
     (REMATCH var1 ... varn)   rematches but will retain var1,...,varn.


                       Hairy Matching Uses
                       ----- -------- ----

     (PR pat)         replaces the CE with the  instantiation  of
                      pat  (substitutes the values of ?-variables
                      and *-variables)
     (PA n P1...Pn)   similar to (A n E1...En)
     (PB n P1...Pn)   similar to (B n E1...En)
     (PAI P1...Pn)    similar to (AI E1...En)
     (PRA exp1 pat)   similar to (R exp1 exp2)
     (TPRA exp1 pat)  similar to (TR exp1 exp2)

                          Other Commands
                          ----- --------

     (SAVE filename <optional ext>)saves the toplevel  expression
                                   in  the file given by the file
                                   specs (will create  files  not
                                   existent), 
     SAVE			   saves the  toplevel expression
				   in the  file last saved in. If
				   there was none, the file spec.
				   is requested.
     (REFILE FOO <file specs>)     replaces the function  FOO  in
                                   the  file  given  by  the file
                                   specs with  that  found  under
                                   the "draft" property of FOO
				   where <file specs> is  of  the
				   form (file <optional ext>).
     (REFILE (FOO1...FOOn)<file specs>)
				   similar to above but refiles
                                   FOO1...FOOn.
     (REFILE (FOO1...FOOn)<infile specs><outfile specs>)
     (REFILE * <infile><optional outfile>) updates every function
				   in  infile.   Note   that  the 
				   specs are as file specs in the
				   vanilla refile above.

                                   similar to above but files the
                                   result in the outfile
     REMEMBER                      puts the  toplevel  expression
                                   under   the  "draft"  property
                                   (preserves  DEFUN  format  and
                                   comments)
     OK                            REMEMBER's  and   EVAL's   the
                                   toplevel            expression
                                   (i.e. defines the function  as
                                   well as remembers it)
     (COMMENT T)                   allows comments to be  in  the
                                   toplevel  expression (uses the
                                   grind-read-table)
     (COMMENT NIL)                 disables above
     HELP                          either    provides     helpful
                                   information or confuses you

                        The Undo Feature
                        --- ---- -------

          The Editor allows the user to "undo" any editing he has
     done.    Thus  if  he  has  made  a  mistake  or  simply  is
     experimenting, he can invoke the undo feature to  undo  each
     step.   However the undoer requires a history of the edit to
     be kept and so uses a lot of space.  Be warned!

     (UNDO T)    enables undoing
     (UNDO n)    enables  undoing  with  only  the  last undoable 
		 commands being saved (initially 6.)
     (UNDO NIL)  disables undoing and flushes the  undoqueue (the
                 history)
     UNDO        undoes the last command.  Successive UNDO's will
                 undo prior edit commands.
     The following commands can be undone:
        ↑ TOP RI RO LI LO NX BK BF DELETE F OK REMEMBER  (COMMENT
        -) (A -) (B -) (R -) (PA -) (PB -) (PAI -) (PBI -) (PL -)
        (PD -) (PRA -) (BF -) (F -) (CR -) (PR -) (AI -)  (BI  -)
        (N -) (N) N (EDPROG -).

                     Programming the Editor
                     ----------- --- ------

***** Flushed 12/4/76 *****
     (EDPROG T)          enables the " read-macro
     (EDPROG NIL)        disables above
*****  End Of Flush   *****
     (EDITCOMMAND A B)   a FEXPR which allows the atom A to  mean
                         B in the Editor.  For instance,
                              (EDITCOMMAND LEN (LENGTH %#CE))
                         tells the Editor that when you type  LEN
                         to  it,  the  length  of the CE is to be
                         reported.

	  It is possible  to write LISP  programs to do  editing:
     one can cause the  editor to evaluate  a command by  saying:
     (%EVALUATE exp),  where  exp  must  EVAL  to  a  valid  edit
     command.  A  simple way  to abbreviate  these calls  to  the
     editor is  to  define a  read  macro which  expands  to  the
     desired call.

          One  may  also  have  an  initialization  file   called
     EDIT.INI which will be read when the Editor is being loaded.
     This file can either contain functions like any  other  LISP
     file or LINKTO statements, which are of the form:

          (LINKTO (<filespec1>)(<filespec2>)...)

     This statement will cause  the  Editor  to  read  the  files
     specified  in order.  Functions and LINKTO statements may be
     interspersed.  No FASLOADs may occur in  the  initialization
     file nor in any of the files LINKTOed.
          A nice  subset of  an  EDIT.INI  file  can  be seen  in
     EDIT.IN[AID,RPG]      which       is      documented      in
     FASMAC.DOC[AID,RPG].  Basically it  uses a hoakey fast  read
     macro facility and  allows one to use  the control/meta keys
     as fast  macros to do atomic edit commands with a minimum of
     key strokes.

          The following global variables are useful:
       %#CE            contains the CE (munging the CE must  be  done
                       using the Editor)
       %TOP-EDIT-EXP   contains the toplevel expression
       %#UNDOLIST      contains the undolist
       %#UNDOFLAG      tells whether or you you are in the undo mode

                        Exiting and Etc.
                        ------- --- ---

     EXIT                exits the Editor (to the LISP toplevel)
     (EDIT)              gets you back to the Editor
     (REMEDIT)           flushes the Editor.
     Any other command is handed to LISP to be EVAL'ed.


                   The Backspace (BS) Package
                   --- --------- ---- -------

          This package, written by Jonl White at the  MITAI  Lab,
     is useful for exploring the environment of a LISP error;  it
     makes use of the EVALFRAME feature documented in the MACLISP
     Reference  Manual  (from here on referred to as the "MACLISP
     Manual").

          When one is in the (*RSET T) mode, a record is kept  of
     the forms and binding environments which lead to the current
     envirnoment.  when an error occurs the  BS  functions  allow
     the  user to examine those environments without jeopardizing
     the current state.  The BS functions can be loaded by doing:

               (FASLOAD BS FAS DSK (MAC LSP))

     and is initialized by:

               (SETUP)

     which puts LISP in the (*RSET (NOUUO T)) mode.

          When a break occurs, one can initialize the environment
     stack with:

               (BS NIL).

     At this point one can start backspacing;   successive  calls
     to  (BS)  will  print  the  form whose evaluation caused the
     evaluation of the current form.  Moreover, the printed  form
     is stored as the value of the atom BS.

          Suppose the break has been caused because the atom  "x"
     is  unbound;   then  the evaluation of "(BS NIL)" will cause
     the following to be printed:

               (APPLY -1273734574 (EVALFRAME (NIL)) -725732747) 

     The next evaluation of (BS) will cause:

               (EVAL -1302734603 (BS) -725732747) 

     One more (BS):

               (APPLY -1345734646 (+INTERNAL-UBV-BREAK ((X))) ..)

     Finally (BS) yields:

               (EVAL -1372734673 X -755732777)


          In the above forms, the first element is either EVAL or
     APPLY,  the  second  is  a  pdl-pointer  specifying  flow of
     control,  the  third  is  the  form  whose  evaluation   (or
     application)  is about to be attempted, and the last element


     is an a-list pointer  specifying  the  binding  environment.
     Note  that  the  use  of  these pointers is explained in the
     MACLISP Manual under the heading "Debugging Aids in LISP".

          Successive (BS)'s will go up one level while (FS)  will
     go  down  one level (where "up" is backwards in time or down
     the stack, and "down" is forwards in time or up the  stack).
     A summary of the available commands:

          (BS)                    Backspace 1 level

          (BS n)                  Backspace n levels

          (BS <function-name>)    Backspace to the first call  to
                                  function-name

          (BS NIL)                Initialize to the  top  of  the
                                  pdl  stack  (furthest  ahead in
                                  time) and (BS) n times

          (BS nil <fn>)           Initialize and do (BS <fn>)

          (BS NIL <fn> n)         Initialize and do (BS <FN> N)

          (FS)                    Go forward (ahead  in  time)  1
                                  level

          (FS NIL)                Initialize to the bottom of the
                                  pdl  stack  (furthest  back  in
                                  time)

          (FS NIL n)              Initialize and do (FS n)

          When in  some  environment  which  one  would  like  to
     explore, the following is useful:

               ↑B
	       <form1>
		  .
		  .
		  .
	       <formn>

     which evaluates each <formi> in the  current  binding  environment
     using  the  last element of the form printed by (BS) and the
     optional second argument to EVAL.

          Finally cntrl-G quits back to the  LISP  toplevel  from
     the break condition.


                         The BRAKE Package
                         --- ----- -------


          This package is useful for  putting  breakpoints  in  a
     function with minimal effort;  the functions to be described
     use the Editor (see above) and should not be used unless the
     Editor  is present.  In fact, these functions use the Editor
     to add the breakpoints.

	  Basically  there  are  only  five  functions:    BRAKE,
     UNBRAKE, BRK, UNBRK, and BRAKEIF (all FEXPRs).  The arguments
     to BRAKE are:

            which function
            where in the function to put the breakpoint
            under what conditions the break should be executed.

          These    arguments    are    specified    by    putting
     indicator-value  pairs  in  the  argument  positions  of the
     function BRAKE.  Example:

       (BRAKE IN QUUX AFTER (SETQ *) NUMBER 3 IF (EQ N 4))

          which says to put a breakpoint  in  the  function  QUUX
     after  the  third  SETQ  and to actually break if n=4.  Note
     that these pairs can be in  any  order  since  the  function
     treats  its  arguments  much  like a property list.  Thus we
     could have said:

       (BRAKE NUMBER 3 AFTER (SETQ *) IF (EQ N 4) IN QUUX).

          Moreover not every one  of  these  pairs  is  necessary
     since defaults are available:

               MISSING   ASSUMED
               -------   -------
               IN        the current function being edited
               IF        IF T
               NUMBER    NUMBER 1
               AFTER     none
               BEFORE    nONE.  

     Therefore 

               (BRAKE AFTER (SETQ A *))

     is legal.  To remove all of the breakpoints  from  FOO,  one
     does:

               (UNBRAKE FOO)

     and if FOO is the function being Edited:

               (UNBRAKE)

     (Note:  after BRAKE  and  UNBRAKE  the  CE  is  the  topmost
     expression   of   the  function  where  the  breakpoint  was


     installed).

          The forms of the breakpoints are as follows:

        (BRAKE IN <name>
                AFTER <pattern> NUMBER n IF <pred>)

     yields

        (PROG2 NIL <form>
               (BREAK (IN <name> AFTER <pattern> NUMBER n)
                      <pred>)).

     ,and

        (BRAKE IN <name>
               BEFORE <pattern> NUMBER n IF <pred>)

     yields

        (PROG2
               (BREAK (IN <name> BEFORE <pattern> NUMBER n)
                      <pred>) <form>).

     where <form> is the n-th form to match <pattern>  using  the
     Editor  matcher.   UNBRAKE  only removes breakpoints of this
     form.

	  BRAKE with no  arguments returns a  list of all  broken
     functions (i.e.  those broken using either BRAKE or BRK.

	  BRK puts  breakpoints at  the beginning  of  functions;
     these breakpoints  are invoked  each  time the  function  is
     called (i.e. there is no associated predicate).  The call to
     BRK looks like (BRK <fn1> <fn2>  ... ), where none of  <fni>
     are evaluated.  

	  UNBRK removes the initial  breakpoint from each of  its
     unevaluated arguments. If  no arguments  are specified,  all
     functions which  have had  breakpoints installed  using  BRK
     will be un-broken.

	  BRAKEIF is  a  fexpr  which  takes  a  function  and  a
     predicate of  no arguments.   The function  will invoke  the
     break whenever the function is  called and the predicate  is
     true.

                        THE DEBUG PACKAGE
                        --- ----- -------


          This package contains  two  functions,  DEBUG  and  BT,
     which  allow  the user to examine LISP's stack (also refered
     to as the  PDL  or  Push-Down-List).   If  the  global  LISP
     variable  *RSET  is  set to T, then the stack will contain a
     detailed record of all the S-expressions  currently  in  the
     process  of  evaluation.  The user should be aware that when
     *RSET is bound to T, LISP runs more  slowly  and  uses  more
     list storage space.  


          The lexpr DEBUG enables one to explore  expressions  on
     the  stack,  examine  local  variable  bindings, and force a
     partially  evaluated  expression  to  prematurely  return  a
     specified  value.   The  function  BT  displays  an indented
     version of the "backtrace".


     Using DEBUG 
     ----- -----


       (DEBUG T)   - Causes  LISP  to  enter  debugging  mode  by
                     setting  *RSET  and  NOUUO to T and snapping
                     the "UUO links".

       (DEBUG NIL) - Sets  *RSET  and  NOUUO  to  nil  to   leave
                     debugging mode (resulting in faster and more
                     efficient evaluation).  

       (DEBUG)     - Enters the debugging function.   DEBUG  will
                     print  the  last  S-expression that LISP was
                     trying to evaluate and wait  for  a  command
                     character  to  be  entered.  After executing
                     the command,  DEBUG  will  wait  for  a  new
                     command  to be entered.  Any of the commands
                     can be preceeded be  an  arbitrary  positive
                     integer,  <n>, which will cause that command
                     to be executed <n> times.


     Commands To Change the Current Expression
     -------- -- ------ --- ------- ----------

	  DEBUG keeps a  pointer to an  element of LISP's  stack,
     the "current expression"  or CE.   One set  of commands  are
     provided to move this pointer, each time displaying the  new
     CE. The  user  can refer  to  the CE  (for  example,  within
     breakpoints while DEBUGging) with the variable %CE

           D - move Down the stack.
               This  command  makes  the  CE   the   next   lower
               S-expression on the stack (i.e. moving us backward
               thru time).

           U - move Up the stack.
               This  command  makes  the  CE  the   next   higher
               expression on the stack (i.e. forward thru time).

           T - jump to the Top of the stack.
               This command makes the CE the  expression  on  the
               top  of  the stack (i.e. the last expression being
               evaluated before the call to DEBUG).


     Commands to Exit the DEBUG function
     -------- -- ---- --- ----- --------

           Q - Quit
               This command exits from  the  debugging  function,
               leaving  the  user  in  the  same  state he was in
               before doing (DEBUG).

           R - Return value.
               This command  forces  the  current  expression  to
               return a specified value.  The user is first asked
               to verify that he wants to force a return from the
               current expression.  If so, he is asked for a form
               to be returned.  This form is evaluated  and  used
               as the return value for the CE.

           C - Re-evaluate current expression.
               This is a variation of the R command in which  the
               current  expression  is re-evaluated.  The user is
               asked  to  verify  that  he  wants   the   current
               expression to be re-evaluated.  


     Other Commands
     ----- --------

           P - Print the current expression.
               DEBUG  normally  displays   expressions   with   a
               PRINLEVEL of 3 and a PRINDEPTH of 5.  This command
               is used to display the current expression  in  its
               entirety.

           S - Sprint the CE.
               This command "pretty-prints" the CE.


           B - Break 
               This  command  causes  LISP  to   break   in   the
               environment   of  the  current  expression.   This
               allows the user to examine local variable bindings
               To continue DEBUGing, the user should type a "$P".

           ? - Help 
               This command prints the list of the commands.



                    A Sample DEBUGing Session
                    - ------ -------- -------

               In this commented LISP session, lines  entered  by
               the user are preceeded by a "*".

       *(DEFUN FACT (X)                         ;POOR LOSER TYPES HIS
           (COND ((= X 0.) I)                   ; PROGRAM WRONG!
           (T (* X (FACT (1- X))))))
        
       *(DEBUG T)                               ;ENTER DEBUGGING MODE
       T
       *(FACT 6)                                ;TRY FUNCTION
       
       
       I UNBOUND VARIABLE
       ;BKPT UNBND-VRBL 
       
       *(DEBUG)                                 ;CALL DEBUGGING FUNCTION 
       
       (+INTERNAL-UBV-BREAK ((I)))              ;LAST THING LISP EVAL'ED
       *D                                       ;MOVE DOWN THE STACK
       I                                        ;NEXT FORM ON STACK 
       *D                                       ;MOVE DOWN AGAIN
       (COND ((= X 0.) I)(T (* X (FACT (1- X))))) 
       *D
       (FACT (1- X)) 
       *D
       (* X (FACT (1- X))) 
       *T                                       ;JUMP TO TOP OF STACK
       (+INTERNAL-UBV-BREAK ((I))) 
       *D                                       ;AND MOVE DOWN ONE
       I 
       *B                                       ;BREAK IN LOCAL ENVIRONMENT
       
       ;BKPT DEBUG
       *(BOUNDP 'I)
       NIL 
       $P                                       ;RETURN FROM BREAKLOOP.
						;$P is <altmode>P
       
       I                                        ;DEBUG DISPLAYS CE AGAIN
       *R                                       ;FORCE A RETURN FROM CE
         FORCE RETURN FROM CURRENT EXPRESSION? 
         TYPE YES OR NO:  YES
         >>>WHAT SHOULD THIS S-EXPRESSION RETURN?  1.
         
       
       240.                                     ;RETURN VALUE OF (FACT 6)
       


       The BT Function
       --- -- --------


	  The lexpr  BT is  used to  display a  backtrace of  the
     function  calls  leading  up   to  the  S-expression   being
     evaluated before a break.  Calling BT with no arguments will
     cause an indented list of all function calls on the stack to
     be printed.  If BT is given an optional numeric argument, n,
     only the last "n" function calls will be displayed.

	  BT does not  display internal calls  used by STEP,  the
     sinlge stepper discussed below.

	  The following example  uses our  losing FACT  function.
     Again, the users input is prefaced with a "*".


          *(DEBUG T)            ;WE MUST BE IN *RSET/NOUUO MODE
          T                     ; FOR (BT) TO WORK
          *(FACT 6)
          
          I UNBOUND VARIABLE 
          ;BKPT UNBND-VRBL 
          
          *(BT)
          
          FACT
           COND
            TIMES
             FACT
              COND
               TIMES
                FACT
                 COND
                  +INTERNAL-UBV-BREAK
          
          * 

     Using DEBUG with STEP
     ----- ----- ---- ----

          DEBUG knows about the Stepper,  and will not print  any
     information put on the stack by STEP.
                        THE STEP PACKAGE
                        --- ---- -------

	  This package  contains three  fexprs, STEP,  STEP-HARD,
     and BREAKIF,  which make  use of  the EVALHOOK  function  in
     MACLISP.  The  STEP  function  provides  a  single  stepping
     facility in  which  LISP displays  each  form before  it  is
     evaluated.  Additional features are provided to  selectively
     enable single  stepping mode  (e.g.   only within  calls  to
     certain functions) and to create "LISP demons".  Demons  can
     also be created with the BREAKIF function.

     Simple use of the STEP function
     ------ --- -- --- ---- --------

     The simplest way to use the STEP function is as follows:

             (STEP T)   - Enter single stepping mode immediately.

             (STEP NIL) - Exit single stepping mode.

          In single stepping mode, LISP will  display  each  form
     before  evaluation  and  pause to accept a command character
     from the user.  When the form is completely  evaluated,  its
     return value is displayed.  The commands are:

                    ⊗S - Evaluate this form  in  single  stepping
                         mode.

                    ⊗X - "Skip".  Do not evaluate  this  form  in
                         single  stepping  mode.  Single stepping
                         mode will be resumed after this form  is
                         evaluated. If a  break  is  encountered,
			 (STEP T) will work.

		    ⊗M - Like ⊗S except it treats the current form
			 as a macro and expands the form without
			 any intermediate stepping.

		    ⊗V - Like ⊗X but performs the expression in
			 *rset = nil mode.

                    ⊗Z - "Skip".  Do not evaluate  this  form  in
                         single  stepping  mode.  Single stepping
                         mode will be resumed after this form  is
                         evaluated. If a  break  is  encountered,
			 (STEP T) will not work.

                    ⊗Q - "Quit".  Exit single stepping mode.  

		    ⊗C - "Continue". Continue evaluation  without
			 stepping   until   the   next  AFTER  or
			 WHEREIN clause is true.

		    ⊗P -  Pretty-print the current form.

		    αP -  Reprints the current form with prinlength
			 and prinlevel increased by one.

		    βP -  Same as above.

		    ⊗B - Breaks STEP at current depth. %CE contains the
			 current expression

     Where "⊗"  means control-meta,  "α" means  control, and  "β"
     means meta.   Typing a  ↑G ("control-G")  at any  time  will
     cause LISP to leave single stepping mode. The stepper stores
     in the global variable %CE, the s-expression currently under
     consideration.

	  One can modify the default prinlevel and prindepth  for
     the Stepper  by setting  the  global variables  STEP-PL  and
     STEP-PD, currently set to 4 and 3 resp.


     An Example
     -- -------


     Lines typed by the user are preceeded by a "*".


          *(SETQ X 5.) 
          5. 
          *(STEP T)                       ;ENTER SINGLE STEPPING MODE
          (T) 
          *(* X (1+ X) (1- (* X X X))) ⊗S ;FORM TO BE EVALED
            X = 5.
            (1+ X) ⊗S
              X = 5.
            6.
            (1- (* X X X)) ⊗S
              (* X X X) ⊗X               ;COMMAND: SKIP SINGLE STEPPING
              125.                       ;          ON THIS FORM.
            124.
          3720.
          3720. 
          (STEP NIL)                     ;EXIT SINGLE STEPPING MODE




     Advanced Features
     -------- --------

	  The STEP function can be instructed to selectively turn
     on single stepping mode only after a particular function has
     been called or only within calls to certain functions.  STEP
     can also  be used  to create  arbitrary "demons"  which  can
     cause LISP to stop and enter a break loop.  This is done  by
     giving STEP from one to three clauses, for example:

               (STEP <clause> <clause> <clause>)

     where the clauses can be one of the following:

          (AFTER FN1 FN2 FN3 ...)
               Causes LISP to enter  single  stepping  mode  only
               after  one  of  the  functions FN1, FN2, etc.  has
               been called.  


          (WHEREIN FN1 FN2 FN3 ...)
               Causes LISP to evaluate in  single  stepping  mode
               only  within calls to the functions FN1, FN2, etc.


          (BREAKIF FORM1 FORM2 ...)
               Will cause the S-expressions  FORM1,  FORM2,  etc.
               to  be evaluated just before every S-expression is
               evaluated.  If any of  these  demons  evaluate  to
               non-NIL,  LISP  will enter a break loop.  When the
               user exits the break loop (with a $P) he  will  be
               asked if he wishes this demon to remain active, or
               be removed from the demon-list.   Evaluation  then
               proceeds in the normal manner.  

     	  (E-STEP (FN A1 ...AN)) sets up to step wherein  FN  and
     then evals (FN A1 ...AN).

	  (UNSTEP (WHEREIN ...))  and (UNSTEP  (AFTER ...))  undo
     the above.

	  (STEP fn1  fn2  ...)  defaults to  (step  (wherein  fn1
     fn2...)). (UNSTEP fn1 fn2 ....) defaults to (UNSTEP (wherein
     fn1 fn2 ...)).

	  The user can cause these clauses default to their  last
     specified values  by  evaluating  (STEP *).   This  is  very
     useful if one has left single stepping mode with a "↑G".


     Using STEP with TRACE
     ----- ---- ---- -----

	  If the Stepper  ever needs to  step through a  function
     which is being traced, the  Stepper will first UNTRACE  that
     function.

     Using STEP with Breakpoints
     ----- ---- ---- -----------


	  If you are evaluating in single stepping mode and enter
     a breakpoint loop, LISP will not be in single stepping  mode
     in that loop.  Conversely, if LISP is not in single stepping
     mode at the top  level, and you evaluate  (STEP T) inside  a
     break-loop, it will have no effect on top level  evaluation.
     In order to  enter single stepping  mode from a  breakpoint,
     the user can evaluate  (STEP) at the  top level.  This  puts
     the single stepper in a mode  where the user can turn it  on
     from within a break loop.


     The BREAKIF Function
     --- ------- --------


	  An additional function, the fexpr BREAKIF, can also  be
     used to set up  LISP demons.  This  function looks like  the
     BREAKIF clause in the STEP function.  Evaluating:

               (BREAKIF FORM1, FORM2, ...  )

     will set up FORM1, FORM2, etc.  as demons, and evaluating:

               (BREAKIF NIL) 



     will disable all the demons.  As with STEP, typing a ↑G will
     also disable the  demons.  Creating demons  with BREAKIF  is
     somewhat  more  efficient  than  using  the  STEP  function,
     however, it can not be used in single stepping mode.

     Step Hard Feature
     ---- ---- -------

	  The feature: (step-hard ...)  is just like step  EXCEPT
     it works HARDER! Now,  working harder is  really a fact,  so
     don't use  it unless  you  need it.   Here's what  it  does:
     suppose you have (defun foo (n) ... (bar ...)  ...) and  foo
     is compiled and bar isn't, and you want to step wherein bar.
     Well, since eval never sees the compiled call to bar, if you
     are stepping-hard, the stepper looks around the FIRST chance
     it gets to see if it is  inside of BAR.  Now, this means  it
     searches the control stack; if it is in bar it prints

		 <in BAR>
		 next-form.


     A Summary
     - -------


       (STEP T)        - Enter single stepping mode.

       (STEP NIL)      - Disable single stepping mode.

       (STEP <CLAUSE>) - Selective single stepping and/or demons.

       (STEP *)        - As  above,  but   use   defaults   (last
                         specified clauses).

       (STEP)          - Enable single stepper so that it can  be
                         turned on from within a break loop.

       (BREAKIF F1...) - Sets up demons F1, ...  .

       (BREAKIF * )    - Re-enables last specified set of demons.

       (BREAKIF NIL)   - Disables demons.

       (STEP-HARD <CL>)- Like STEP, but works harder.

       <control>G      - Exits single stepping/demon mode.

		      Features and Meta-features
		      -------- --- ---- --------

	  The Maclisp  at  SAIL  contains  several  autoload-able
     initial functions of use in  debugging. First, EDIT has  the
     autoload property, and  thus the  Editor may be  run at  any
     time. Second, there  is a  function of  no arguments  called
     HELP, which is autloadable.  This function merely serves  to
     load  HELP.FAS[MAC,LSP],  which  is   a  file  of   autoload
     properties for various functions. Among these functions are:

	DEBUG, BT	Debug routines discussed above

	STRING		Readmacro for " (equivalent to |)

	MACRO, MACRODEF	Macro definition macros
	MACROBIND	
	

	PRLISP, PRECESS	Prlisp package from MIT

	MACEX		File macro expansion package, useful
			for preparing Maclisp files to run under
			Interlisp

	STEP, BREAKIF	Step package discussed above.
	STEP-HARD

	REVIEW, INDEX	MIT indexing program

	INPUSH,INPOP	File requiring routines.
	REQUIRE		(INPUSH and INPOP are OLDIO functions only)

	SETUP		Jon White Backspace Package.

	CGOL		Pratt's CGOL.

	BRAKE, BRK,	Brake package  discussed above
	UNBRAKE, UNBRK,
	BRAKEIF

	TRACEQ		SETQ tracer.

	DIR, DIRECT,	Directory package, including > hack routines
	UGREAT

	ET		Routines to run E as a subjob

	MAIL		Routines to MAIL from Maclisp

	LOADCR,LOADED	Line editor loading routines
	ADDED, INITED
	
				String
				------

	  The string  macro  simply  allows the  user  to  use  "
     wherever | is appropriate in normal Maclisp.


			       Macrodef
			       --------

	  MACRODEF is  a macro  used to  define macros!  The  two
     normal  ways  of  using   it  are  with  parenthesized   and
     unparenthesized arguments  (like  exprs and  lexprs).   With
     parenthesized arguments,  the  individual  formal  arguments
     have the corresponding actual arguments substituted for them
     in the body of  the macro. For instance,  one might want  to
     have a macro  to do  simple stack  manipulations, where  the
     underlying implementation is in terms of lists. So, we might
     have:

	(MACRODEF PUSH (THING PDL) (SETQ PDL (CONS THING PDL)))

	(MACRODEF POP (PDL) (PROG2 NIL (CAR PDL) (SETQ PDL (CDR PDL))))

     Code using these macros would be something like:

	       Macro call			   Expansion
	       ----- ----			   ---------

	(PUSH (PLUS FOO BAR) QUUX)  ===>  (SETQ QUUX (CONS (PLUS FOO BAR) QUUX))

	(POP QUUX)		    ===>  (PROG2 NIL (CAR QUUX) (SETQ QUUX (CDR QUUX)))

     where the  forms  on  the  right  are  the  results  of  the
     macro-expansion (i.e.  the actual code executed).

	  With an unparenthesized  argument, the single  argument
     is bound to the  CDR of the calling  form, and that form  is
     then substituted for the formal argument throughout the body
     of the macro. Thus:

	(MACRODEF PROG1 X (PROG2 NIL . X)) 

     is a  macro to  do  the obvious  thing for  PROG1's.  Notice
     particularly that the "." situation is handled correctly.

	  MACRODEF's with  more than  one form  in the  body  are
     handled by adding an  explicit PROGN if necessary.  Finally,
     remember that substitutions for  formal parameters is  done,
     not lambda-binding.  So arguments  are re-computed  wherever
     their formal  parameters appear  in  the defining  form.  To
     solve this problem, one  can explicilty lambda-bind.  Macros
     within MACRODEF's are allowed.

	  MACRODEF with parenthesized name (i.e. (macrodef (foo) ...)) will
    create a compilable macro.
				MACRO
				-----

	  MACRO is another macro definition macro, but allows for
     fancier argument handling.  Used in  conjunction with  CODE,
     this  definition  facility   permits  the  programmer   wide
     latitude  in  defining  his  syntactic  sugar.  The  binding     
     mechanism used  is based  on  the Editor's  pattern  matcher
     discussed above: one can invoke  the pattern matcher on  the
     CDR of  the  responsible  form. The  side  effects  of  this
     process (namely, setting ? and  * variables) can be used  by
     CODE to  produce code  based on  the input  in a  convenient
     manner. For example, here is a macro to do lambda-binding in
     a more readable format:

	(macro let (*vars ← *vals do *form)
	 (code ((lambda (*vars) *form) *vals)))

     An example of the use is:

	(let foo bar quux ← (plus x y z)  'foo quux do
	 <hack foo, bar, and quux>) 

		===> ((lambda (foo bar quux)
		      <hack foo, bar, and qquux>)
		      (plus x y z) 'foo quux)

	  CODE, a FEXPR,  is simply  the instantiation  mechanism
     talked about in the Editor  section. CODE takes a form,  and
     replaces all occurrences of variables whose first  character
     is ? with its  LISP value. All forms  with * as their  first
     character have their values (lists) spliced in wherever they
     occur in  the form.   Here's an  example of  this  facitlity
     defining a hairy FOR loop:

;;; (FOR X {IN,ε} L {DO,APPEND,COLLECT,CONC,SELECT} form {RETURN} form)

(macro for (*x ($r ? (lambda(q) (memq q '(in ε)))) *l ($r ?verb (lambda (q)
					(memq q '(do collect append conc select)))) *form)
 ((lambda (*form1 *form2)
   (%match '(*form1 return *form2) *form)
	(cond ((eq ?verb 'append) 
	       (cond (*form2 
	        (code (progn (mapcan (function (lambda (*x)
					((lambda (q) (cond (q (ncons q))))
		 			 (progn *form1)))) *l) *form2)))
		(t (code (mapcan (function (lambda(*x)((lambda(q)(cond (q (ncons q))))
					(progn *form1)))) *l)))))  
	      ((eq ?verb 'conc)
	       (cond (*form2
	 	(code (progn (mapcan (function (lambda (*x)
						(progn *form1))) *l) *form2)))
		     (t (code (mapcan (function (lambda (*x)
					         (progn *form1))) *l)))))
	      ((eq ?verb 'select)
	       (cond (*form2
	 	(code (progn (mapcan (function (lambda (*x)
						(and *form1 (list *x)))) *l) 
					        *form2)))
		     (t (code (mapcan (function (lambda (*x)
					         (and *form1 (list *x)))) *l)))))

	      (t ((lambda (?verb)
		   (cond (*form2 
		    (code (progn (?verb (function (lambda (*x) *form1)) *l) *form2)))
			 (t
		    (code (?verb (function (lambda (*x) *form1)) *l) )))) 
		  (cond ((eq ?verb 'do) 'mapc)
			(t 'mapcar)))))) 
  *form nil))
 
	MACRO with a parenthesized name will create a compilable macro ala MACRODEF.
		   Further MACRO/MACRODEF features
		   ------- -------------- --------

	  There are  some  additional  features  associated  with
     these macro  definition  facilities. First  of  all,  normal
     macro expansion is  destructive; that is,  the form  causing
     macro expansion is actually replaced (via RPLACA and RPLACD)
     so that the subsequent passes  over the code does not  cause
     re-expansion.   However,   secondly,   in  *RSET   T   mode,
     destructive expansion is  inhibited, so  while DEBUGging  or
     STEPping, one can see both the call on the macro and on  the
     expanded code.

	  In addition,  if  the global  variable  SAVE-MACROS  is
     non-nil, then the original form and its expansion are stored
     somewhere so that (UNCAN) will un-expand all macros.

	  %%CLOBBER-MACROS%% will  cause  destructive  macros  to
     destroy regardless of *REST.
				MACEX
				-----

	  MACEX,  a   FEXPR,   expects  an   EREAD   style   file
     specification as its argument and  produces a file with  all
     known macros expanded as a side effect. The extension of the
     file produced  is  .EXP  on  the  aliased  directory.  MACEX
     attempts to understand REQUIRE's,  but is not guaranteed  to
     work in all hairy cases. A tactic useful in such cases is to
     MACEX the file(s) in question from within a core image  with
     the file(s)  loaded (and  with all  the macros  defined,  of
     course). E.g. (MACEX FOO BAR DSK (AID RPG)).
			       REQUIRE
			       -------

	  REQUIRE is  a FEXPR  taking  a file  specification  and
     having the effect  of splicing  that file stream  in at  the
     point of call.  Actually, REQUIRE  pushes the  state of  the
     file open on  channel 3, PRINT-EVAL-READs  each form in  the
     file given by its  arguments, and finally  pops back to  the
     old file.  Nesting to 23  levels is permitted (SAIL  monitor
     restriction). REQUIRE  looks  at  the value  of  the  global
     variable READ, and uses the function pointed to rather  than
     READ if it is non-nil.   The file specification is the  same
     as that expected by EREAD.

	  INPUSH is a FEXPR which takes a file specification  and
     pushes the state of the file open on channel 3 and positions
     the read pointer to  the first non-E  directory item in  the
     file specified. This function is used by REQUIRE.

	  INPOP is an  EXPR of  no arguments  which restores  the
     file state to that just after the point of call of the  last
     INPUSH EVALed.  This  function  is used  by  REQUIRE.  These
     functions are in OLDIO only.
				DIRECT
				------

	  DIRECT is an EXPR of two arguments. The first  argument
     is a project, and the second is a programmer. The result  is
     a list of files in the  directory specified by the ppn.  For
     example, (DIRECT 'AID  'RPG) returns a  list such as:

	((edit /113) (option txt)...)

	  DIR is a FEXPR taking either a full ppn spec, just  the
     project, or  no  ppn  spec  and performs  a  DIRECT  on  the
     specified directory. If no  programmer is pecified, the  the
     logged in  programmer is  assumed.  If no  specification  is
     given, then the aliased ppn is assumed.

	  UGREAT is a FEXPR taking  three arguments: a file  name
     (no extension), a project, and a programmer, and returns the
     highest  numbered  extension  for  that  file  name  in  the
     directory specified. No defaulting is performed.
				  ET
				  --

	  ET is an LEXPR expecting  a file specification and  two
     optional arguments, a  page number  and a  line number.  The
     file specification is of the form (file ext (p pn)) and  all
     but the file are optional.  The function causes E, the  SAIL
     editor to be run on the specified file and the cursor to  be
     positioned at the designated  page and line.  If no line  is
     given, the top of the page is assumed; if no page is  given,
     page 1 is assumed. αXrun (α = control) causes the Maclisp to
     be resumed.
				 MAIL
				 ----

	  MAIL is a FEXPR expecting two arguments, a  destination
     and  a  message.   The  destination  is  an  atomic   symbol
     specifying a  programmer (i.e.  RPG) and  the message  is  a
     string (i.e.  |Hello, Ralph|  or  "Hello, Chump").   If  the
     message or  both arguments  are  missing, MAIL  prompts  for
     them.  MAIL uses the MAIL  phantom, and so does not  deliver
     immediately (neither does the Post Office, though).

	  Note that the arguments  to MAIL are EVALed  internally
     unless they are prompted for!
			 Line Editor Loading
			 ---- ------ -------

	  INITED is an EXPR of no arguments which initializes  an
     internal buffer (must be done initially)

	  ADDED is an EXPR of two  arguments, a form and a  flag.
     If the flag  is nil, then  the form is  put in the  internal
     buffer without slashifying special  characters. If the  flag
     is non-nil, special characters are slashified.

	  LOADED is  an  EXPR  of no  arguments,  and  loads  the
     contents of the internal buffer into the line editor.